package cn.shop.thiredparty.service;

import cn.shop.thiredparty.config.OSSConfig;
import cn.shop.thiredparty.entity.BytesInputStream;
import cn.shop.thiredparty.entity.BytesOutputStream;
import cn.shop.thiredparty.entity.Metadata;
import cn.shop.thiredparty.util.MetadataHelper;
import com.aliyun.oss.OSS;
import com.aliyun.oss.ServiceException;
import com.aliyun.oss.model.GenericRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil2;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;

/**
 * @author : 李一涵
 * @date : Created in 2022/5/18 11:24
 * @description :
 */
@Service("ossService")
public class AliOssService {

    @Resource
    private OSS oss;
    @Resource
    private OSSConfig config;
    @Resource
    private MimeUtil2 mimeUtil;

    /**
     * 上传一个文件。返回生成的文件名。
     *
     * @param metadata 文件元数据，包括文件名、类型等信息
     * @param content 文件内容
     * @return 生成的文件名
     */
    public String upload(Metadata metadata, InputStream content) {
        String filename;
        if (metadata == null)
            metadata = new Metadata();
        try {
            BytesInputStream data = null;
            if (content instanceof BytesInputStream)
                data = (BytesInputStream) content;
            else {
                BytesOutputStream bos = new BytesOutputStream();
                bos.readFrom(content);
                bos.close();
                data = bos.toInputStream();
            }
            // 检测Mime type
            MimeType mimeType = findMimeType(data.asStream(), metadata.getFilename());
            if (mimeType != null)
                metadata.setContentType(mimeType.toString());

            // 根据内容生成文件名
            try {
                filename = DigestUtils.md5Hex(data.asStream());
            } catch (Exception e) {
                throw new ServiceException("上传文件失败");
            }
            String extension = extractExtension(metadata.getFilename());
            if (extension != null)
                filename += extension;
            metadata.setFilename(filename);

            // 检查该文件是否已存在
            GenericRequest headreq = new GenericRequest(config.getBucketName(), filename);
            boolean exists = oss.doesObjectExist(headreq);
            if (!exists) {
                // 文件不存在
                // 上传文件
                ObjectMetadata om = MetadataHelper.toObjectMetadata(metadata);
                om.setContentLength(data.length());
                PutObjectRequest req = new PutObjectRequest(config.getBucketName(), filename, data.asStream(), om);
                PutObjectResult putObjectResult = oss.putObject(req);
                String etag = putObjectResult.getETag();
                if (etag == null || etag.isEmpty())
                    // 上传失败
                    filename = null;
            }
        } catch (Exception e) {
            throw new ServiceException("上传文件失败", e);
        }

        return filename;
    }

    /**
     * 上传网络资源。返回生成的文件名。
     *
     * @param url 资源URL
     * @return 生成的文件名
     */
    public String copy(URL url) {
        String path = url.getPath();
        if (path != null) {
            int slash = path.lastIndexOf('/');
            if (slash >= 0)
                path = path.substring(slash + 1);
        }
        try {
            BytesOutputStream bos = new BytesOutputStream();
            bos.readFrom(url.openStream());
            bos.close();
            BytesInputStream data = bos.toInputStream();
            Metadata metadata = new Metadata();
            metadata.setFilename(path);
            return upload(metadata, data);
        } catch (Exception e) {
            throw new ServiceException("拷贝网络图片失败", e);
        }
    }

    @SuppressWarnings("unchecked")
    private MimeType findMimeType(InputStream file, String filename) {
        MimeType type = null;
        Collection<MimeType> types = null;
        if (filename != null && !filename.isEmpty())
            types = mimeUtil.getMimeTypes(filename);
        if (types != null && !types.isEmpty())
            type = types.iterator().next();
        if (type == null ||
                MimeUtil2.UNKNOWN_MIME_TYPE.equals(type)) {
            types = mimeUtil.getMimeTypes(file);
            if (!types.isEmpty())
                type = types.iterator().next();
        }
        return MimeUtil2.UNKNOWN_MIME_TYPE.equals(type) ? null : type;
    }

    private static String extractExtension(String filename) {
        if (filename != null && !filename.isEmpty()) {
            // 从文件名最后开始，往前找第一个非字母数字字符
            int dot = filename.length() - 1;
            while (dot >= 0) {
                char c = filename.charAt(dot);
                if (c >= 'a' && c <= 'z'  ||
                        c >= 'A' && c <= 'Z' ||
                        c >= '0' && c <= '9')
                    dot--;
                else
                    break;
            }
            if (dot >= 0)
                return "." + filename.substring(dot + 1).toLowerCase();
        }
        return null;
    }
}
